<template>
	<view class="main">
		<view class="title">{{ device.name }}</view>
		<view class="connect">
			<view class="btn" @tap="createConnection" :class="btnClass">
				<view class="txt">{{ btnTxt }}</view>
			</view>
		</view>
		<view class="services">
			<view class="title">服务列表</view>
			<view class="list">
				<view
					v-for="(item, index) in services" :key="index" class="service"
					@tap="selectService(item)"
				>
					<view class="item name">{{ item.uuid }}</view>
					<view class="item primary">{{ item.isPrimary ? '主' : '次' }}</view>
				</view>
			</view>
		</view>
		<view class="modal" v-if="characteristics && characteristics.length > 0"
			@tap="clearCharacteristic"
		>
			<view class="characteristics" @click.stop>
				<view class="title">特征值列表</view>
				<view class="list">
					<view class="characteristic" v-for="(item, index) in characteristics" :key="index" 
					@tap="selectCharacteristic(item)"
					>
						<view class="name">{{ item.uuid }}</view>
						<view class="values">
							<text class="item" :class="item.properties.read ? 'working' : 'not-work'" @tap="readCharacteristic(item.properties.read)">可读</text>
							<text class="item" :class="item.properties.write ? 'working' : 'not-work'" @tap="writeCharacteristic(item.properties.write)">可写</text>
							<text class="item" :class="item.properties.indicate ? 'working' : 'not-work'">指示</text>
							<text class="item" :class="item.properties.notify ? 'working' : 'not-work'" @tap="notifyCharacteristic(item.properties.notify)">通知</text>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	// #ifdef APP-HARMONY
	import { stringToArrayBuffer } from '@/uni_modules/hw-file-picker'
	// #endif
	export default {
		onLoad(options) {
			this.device = {
				id: options.deviceId,
				name: options.deviceName
			}
			// 自动尝试建立连接
			this.createConnection(() => {
				// 获取服务列表
				this.getServices()
			})
		},
		onHide() {
			// 关闭连接
		},
		computed: {
			btnClass() {
				console.log(this.isConnected + '-' + this.isLoading + '-' + this.flag)
				if (this.isConnected) {
					return 'connected'
				} else {
					if (this.isLoading) {
						return this.flag ? 'loaded' : 'unloaded'
					} else {
						return 'un-connected'
					}
				}
			},
			btnTxt() {
				if (!this.isConnected) {
					// 没连接上
					if (this.isLoading) {
						return '连接中'
					} else if (this.connectError) {
						return this.connectError
					} else {
						return '未连接'
					}
				} else {
					return this.rssiValue ? ('rssi: ' + this.rssiValue) : '连接已建立'
				}
			}
		},
		data() {
			return {
				isConnected: false,
				services: [],
				// 当前选中的设备
				device: null,
				service: null,
				characteristics: [],
				characteristic: null,
				timer: null,
				rssiTimer: null,
				isLoading: false,
				flag: false,
				connectError: '',
				rssiValue: null
			}
		},
		methods: {
			createConnection(callback) {
				this.isLoading = true
				uni.createBLEConnection({
					deviceId: this.device.id,
					timeout: 20000,
					success: () => {
						console.log("uni-ble", "连接成功")
						// this.selected.state = true
						this.isConnected = true
						callback?.()
					},
					fail: (error) => {
						console.log("uni-ble", "连接报错：", JSON.stringify(error))
						// 连接中断
						this.isLoading = false
						this.connectError = '连接报错'
						setTimeout(() => this.connectError = '', 2000)
					}
				})
				uni.onBLEConnectionStateChange((state) => {
					console.log("uni-ble 状态更新：", JSON.stringify(state));
					this.isConnected = state?.connected
					if (this.isLoading && this.isConnected) {
						this.isLoading = false
					}
				})
			},
			closeConnection() {
				uni.closeBLEConnection({
					deviceId: this.device.id,
					success: () => {
						console.log("uni-ble", "成功断开连接")
						// this.selected.state = false;
					},
					fail: (err) => {
						console.error(JSON.stringify(err), 'uni-ble')
					}
				})
			},
			setBLEMTU() {
				uni.setBLEMTU({
					deviceId: this.device.id,
					mtu: 500,
					success: () => {
						console.log("Set ble mtu success", "uni-ble")
						uni.showModal({
							title: '提示框',
							content: '设置成功'
						})
					},
					fail: (err) => {
						console.error(JSON.stringify(err), 'uni-ble')
						uni.showModal({
							title: '错误提示',
							content: JSON.stringify(err)
						})
					}
				})
			},
			getRssi() {
				uni.getBLEDeviceRSSI({
					deviceId: this.device.id,
					success: (res) => {
						console.log("uni-ble", "读取RSSI值", JSON.stringify(res))
						this.rssiValue = res.RSSI
					},
					fail: (err) => {
						console.error(JSON.stringify(err), 'uni-ble')
						this.rssiValue = undefined
					}
				})
			},
			getServices() {
				uni.getBLEDeviceServices({
					deviceId: this.device.id,
					success: (result) => {
						console.log("uni-ble", JSON.stringify(result));
						this.services = result.services
					},
					fail: (err) => {
						console.error(JSON.stringify(err), 'uni-ble')
						uni.showModal({
							title: '错误提示',
							content: JSON.stringify(err)
						})
					}
				})
			},
			selectService(service) {
				uni.getBLEDeviceCharacteristics({
					deviceId: this.device.id,
					serviceId: service.uuid,
					success: (result) => {
						console.log("uni-ble 特征值", JSON.stringify(result))
						this.service = result
						this.characteristics = result.characteristics
						this.characteristic = null
					},
					fail: (err) => {
						console.error(JSON.stringify(err), 'uni-ble')
						uni.showModal({
							title: '错误提示',
							content: JSON.stringify(err)
						})
					}
				})
			},
			selectCharacteristic(characteristic) {
				this.characteristic = characteristic;
			},
			clearCharacteristic() {
				this.characteristic = null
				this.characteristics = []
			},
			writeCharacteristic(useable) {
				if (!useable) {
					return
				}
				console.log('uni-ble', 'prepare to write characteristic value')
				const value = stringToArrayBuffer('hello world');
				uni.writeBLECharacteristicValue({
					deviceId: this.device.id,
					serviceId: this.service.uuid,
					characteristicId: this.characteristic.uuid,
					value: value,
					writeType: "writeNoResponse",
					success: () => {
						console.log("uni-ble", "写入特征值", "写入成功")
						uni.showModal({
							title: '提示框',
							content: '写入成功'
						})
					},
					fail: (err) => {
						console.error(JSON.stringify(err), 'uni-ble')
						uni.showModal({
							title: '错误提示',
							content: JSON.stringify(err)
						})
					}
				})
			},
			notifyCharacteristic(useable) {
				if (!useable) {
					return
				}
				uni.onBLECharacteristicValueChange(result => {
					console.log("uni-ble", "特征值变化", JSON.stringify(result));
				})
				uni.notifyBLECharacteristicValueChange({
					deviceId: this.device.id,
					serviceId: this.service.uuid,
					characteristicId: this.characteristic.uuid,
					state: true,
					success: () => {
						console.log('uni-ble', "通知订阅成功")
						uni.showModal({
							title: '提示框',
							content: "通知订阅成功"
						})
					},
					fail: (err) => {
						console.error(JSON.stringify(err), 'uni-ble')
						uni.showModal({
							title: '错误提示',
							content: JSON.stringify(err)
						})
					}
				})
			},
			readCharacteristic(useable) {
				if (!useable) {
					return
				}
				uni.onBLECharacteristicValueChange(result => {
					console.log("uni-ble", "特征值变化", JSON.stringify(result));
					uni.showModal({
						content: `特征值：`
					})
				})
				uni.readBLECharacteristicValue({
					deviceId: this.device.id,
					serviceId: this.service.uuid,
					characteristicId: this.characteristic.uuid,
					success: () => {
						console.log('uni-ble', "读取成功")
					},
					fail: (err) => {
						console.error(JSON.stringify(err), 'uni-ble')
					}
				})
			}
		},
		watch: {
			isLoading() {
				if (this.isLoading) {
					this.timer = setInterval(() => {
						this.flag = !this.flag
					}, 1000)
				} else{
					clearInterval(this.timer)
					this.flag = true
				}
			},
			isConnected() {
				if (this.isConnected) {
					this.rssiTimer = setInterval(() => {
						const value = Math.floor(new Date() / 1000)
						console.log('ble rssi random value: ' + value)
						if ((value % 10) % 2 === 0) {
							this.getRssi()
						} else {
							this.rssiValue = undefined
						}
					}, 3000)
				} else {
					clearInterval(this.rssiTimer)
				}
			}
		}
	}
</script>

<style>
	.main {
		width: 100%;
		height: 100%;
		background-color: #eee;
	}
	.main>.title {
		height: 50px;
		line-height: 50px;
		border-radius: 10px;
		padding-left: 10px;
		margin: 0 10px 10px 10px;
		background-color: #fff;
	}
	.main .connect {
		width: 100%;
	}
	.main .connect .btn {
		margin: 30px auto;
		width: 200px;
		height: 200px;
		border-radius: 100px;
		transition: background-color 1s ease;
	}
	.main .connect .unloaded {
		background-color: #ccc;
	}
	.main .connect .connected {
		background-color: red;
	}
	.main .connect .loaded {
		background-color: red;
	}
	.main .connect .un-connected {
		background-color: #ccc;
	}
	.main .connect .btn .txt {
		width: 100%;
		height: 100%;
		line-height: 200px;
		text-align: center;
		color: #fff;
	}
	.main .services {
		margin: 0 10px;
		padding: 10px;
		box-sizing: border-box;
		border-radius: 10px;
		background-color: #fff;
	}
	.main .services .title {
		padding: 10px 0;
		font-size: 18px;
	}
	.main .services .list .service {
		padding: 10px 0;
	}
	.main .services .list .service .name {
		font-size: 14px;
	}
	.main .services .list .service .primary {
		float: right;
	}
	.main .services .list .service .item {
		display: inline-block;
	}
	.modal {
		position: fixed;
		width: 100%;
		height: 100%;
		top: 0;
		right: 0;
		bottom: 0;
		left: 0;
		background-color: rgba(0, 0, 0, 0.5)
	}
	.modal .characteristics {
		position: fixed;
		width: 100%;
		min-height: 350px;
		bottom: 0;
		padding: 10px 10px 100px 10px;
		box-sizing: border-box;
		border-radius: 10px;
		background-color: #fff;
		box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5)
	}
	.modal .characteristics .title {
		padding: 10px 0;
		font-size: 18px;
	}
	.modal .characteristics .list .characteristic {
		padding: 10px 0;
	}
	.modal .characteristics .list .characteristic .name {
		font-size: 14px;
	}
	.modal .characteristics .list .characteristic .values {
		margin-top: 10px;
	}
	.modal .characteristics .list .characteristic .values .item {
		margin-right: 20px;
	}
	.modal .characteristics .list .characteristic .working {
		color: steelblue
	}
	.modal .characteristics .list .characteristic .not-work {
		color: #aaa
	}
</style>